﻿using System.Threading;
using System.Collections;
namespace System.Web
{
    public partial class NetHttpApplication
    {
        internal class ApplicationNetStepManager : NetStepManager
        {
            private int _currentStepIndex;
            private int _endRequestStepIndex;
            private IExecutionStep[] _execSteps;
            private int _numStepCalls;
            private int _numSyncStepCalls;
            private WaitCallback _resumeStepsWaitCallback;

            public ApplicationNetStepManager(NetHttpApplication application)
                : base(application) { }

            internal override void BuildSteps(WaitCallback stepCallback)
            {
                var steps = new ArrayList();
                var app = _application;
                app.CreateEventExecutionSteps(EventBeginRequest, steps);
                app.CreateEventExecutionSteps(EventAuthenticateRequest, steps);
                app.CreateEventExecutionSteps(EventDefaultAuthentication, steps);
                app.CreateEventExecutionSteps(EventPostAuthenticateRequest, steps);
                app.CreateEventExecutionSteps(EventAuthorizeRequest, steps);
                app.CreateEventExecutionSteps(EventPostAuthorizeRequest, steps);
                app.CreateEventExecutionSteps(EventResolveRequestCache, steps);
                app.CreateEventExecutionSteps(EventPostResolveRequestCache, steps);
                steps.Add(new MapHandlerExecutionStep(app));
                app.CreateEventExecutionSteps(EventPostMapRequestHandler, steps);
                app.CreateEventExecutionSteps(EventAcquireRequestState, steps);
                app.CreateEventExecutionSteps(EventPostAcquireRequestState, steps);
                app.CreateEventExecutionSteps(EventPreRequestHandlerExecute, steps);
                steps.Add(new CallHandlerExecutionStep(app));
                app.CreateEventExecutionSteps(EventPostRequestHandlerExecute, steps);
                app.CreateEventExecutionSteps(EventReleaseRequestState, steps);
                app.CreateEventExecutionSteps(EventPostReleaseRequestState, steps);
                //steps.Add(new CallFilterExecutionStep(app));
                //app.CreateEventExecutionSteps(EventUpdateRequestCache, steps);
                //app.CreateEventExecutionSteps(EventPostUpdateRequestCache, steps);
                _endRequestStepIndex = steps.Count;
                app.CreateEventExecutionSteps(EventEndRequest, steps);
                steps.Add(new NoopExecutionStep());
                _execSteps = new IExecutionStep[steps.Count];
                steps.CopyTo(_execSteps);
                _resumeStepsWaitCallback = stepCallback;
            }

            internal override void InitRequest()
            {
                _currentStepIndex = -1;
                _numStepCalls = 0;
                _numSyncStepCalls = 0;
                _requestCompleted = false;
            }

            internal override void ResumeSteps(Exception error)
            {
                bool completed = false;
                bool completedSynchronously = true;
                var application = _application;
                var context = application.Context;
                ThreadContext context2 = null;
                var syncContext = context.SyncContext;
                lock (_application)
                {
                    try { context2 = application.OnThreadEnter(); }
                    catch (Exception exception) { if (error == null) error = exception; }
                    //
                    try
                    {
                    Label:
                        if (syncContext.Error != null)
                        {
                            error = syncContext.Error;
                            syncContext.ClearError();
                        }
                        if (error != null)
                        {
                            application.RecordError(error);
                            error = null;
                        }
                        if (syncContext.PendingOperationsCount > 0)
                            syncContext.SetLastCompletionWorkItem(this._resumeStepsWaitCallback);
                        else
                        {
                            if ((_currentStepIndex < _endRequestStepIndex) && ((context.Error != null) || _requestCompleted))
                                _currentStepIndex = _endRequestStepIndex;
                            else
                                _currentStepIndex++;
                            if (_currentStepIndex >= _execSteps.Length)
                                completed = true;
                            else
                            {
                                _numStepCalls++;
                                context.SyncContext.Enable();
                                error = application.ExecuteStep(_execSteps[_currentStepIndex], ref completedSynchronously);
                                completedSynchronously = true;
                                if (completedSynchronously)
                                {
                                    _numSyncStepCalls++;
                                    goto Label;
                                }
                            }
                        }
                    }
                    finally
                    {
                        if (context2 != null)
                            try { context2.Leave(); }
                            catch { }
                    }
                }
                if (completed)
                {
                    application.AsyncResult.Complete(_numStepCalls == _numSyncStepCalls, null, null);
                    application.ReleaseAppInstance();
                }
            }
        }
    }
}
